package net.cl.support.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import net.cl.mvc.pagination.Pageable;
import net.cl.mvc.pagination.Pagination;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * 扩展了{@link org.springframework.orm.hibernate3.support.HibernateDaoSupport}<br>
 * 可以让业务层或dao层的类继承本类以方便的进行hibernate的相关操作<br>
 * 依赖：<b>spring 3.x</b> <b>hibernate 3.x</b>
 * 
 * @author CaoLei
 */
public class BaseDao extends HibernateDaoSupport {

	protected static final Log log = LogFactory.getLog(BaseDao.class);
	private static final String COUNT_SQL_PRE = "select count(*) ";

	public Object save(Object entity) {
		getHibernateTemplate().save(entity);
		return entity;
	}

	public Object update(Object entity) {
		getHibernateTemplate().update(entity);
		return entity;
	}

	public Object merge(Object entity) {
		return getHibernateTemplate().merge(entity);
	}

	public void delete(Object obj) {
		getHibernateTemplate().delete(obj);
	}

	public Object get(Class<?> clazz, Serializable id) {
		return getHibernateTemplate().get(clazz, id);
	}

	public Object load(Class<?> clazz, Serializable id) {
		return getHibernateTemplate().load(clazz, id);
	}

	public List<?> find(String hql) {
		return getHibernateTemplate().find(hql);
	}

	public List<?> find(String hql, Object value) {
		return getHibernateTemplate().find(hql, value);
	}

	public List<?> find(String hql, Object[] values) {
		return getHibernateTemplate().find(hql, values);
	}

	public Object queryForObject(String hql) {
		return find(hql).get(0);
	}

	public Object queryForObject(String hql, Object value) {
		return find(hql, value).get(0);
	}

	public Object queryForObject(String hql, Object[] values) {
		return find(hql, values).get(0);
	}

	public List<?> findByNamedQuery(String queryName) {
		return getHibernateTemplate().findByNamedQuery(queryName);
	}

	public List<?> findByNamedQuery(String queryName, Object value) {
		return getHibernateTemplate().findByNamedQuery(queryName, value);
	}

	public List<?> findByNamedQuery(String queryName, Object[] values) {
		return getHibernateTemplate().findByNamedQuery(queryName, values);
	}

	public Object findByNamedQueryForObject(String queryName) {
		return findByNamedQueryForObject(queryName, (Object[]) null);
	}

	public Object findByNamedQueryForObject(String queryName, Object value) {
		return findByNamedQueryForObject(queryName, new Object[] { value });
	}

	public Object findByNamedQueryForObject(String queryName, Object[] values) {
		List<?> list = getHibernateTemplate().findByNamedQuery(queryName, values);
		if (list == null || list.size() == 0)
			return null;
		else
			return list.get(0);
	}

	public void flush() {
		getHibernateTemplate().flush();
	}

	public Pageable getPageList(Pagination paging, String hql) {
		return getPageList(paging, hql, (Object[]) null);
	}

	public Pageable getPageList(Pagination paging, String hql, Object[] values) {
		paging.setItemsCount(getHqlQueryCount(hql, values));
		paging.setItems(getListForPage(hql, values, paging.getStartIndex(), paging.getPageSize()));
		return paging;
	}

	public int getHqlQueryCount(String hql, Object[] values) {
		int i = hql.toLowerCase().lastIndexOf(" from ");
		if (i > -1)
			hql = hql.substring(i + 1);
		i = hql.toLowerCase().indexOf(" order by ");
		if (i > -1)
			hql = hql.substring(0, i);
		return ((Long) queryForObject(COUNT_SQL_PRE + hql, values)).intValue();
	}

	private List<?> getListForPage(final String hql, final Object[] values, final int offset, final int length) {
		List<?> list = getHibernateTemplate().execute(new HibernateCallback<List<?>>() {
			public List<?> doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (values != null && values.length > 0) {
					for (int i = 0; i < values.length; i++) {
						query.setParameter(i, values[i]);
					}
				}
				query.setFirstResult(offset);
				query.setMaxResults(length);
				return query.list();
			}
		});
		return list;
	}

	/**
	 * @deprecated 有空需要重写
	 */
	public Pageable getPageList(final Pagination paging, final DetachedCriteria detachedCriteria) {
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Pageable>() {
			public Pageable doInHibernate(Session session) throws HibernateException, SQLException {
				Criteria criteria = detachedCriteria.getExecutableCriteria(session);
				int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
				criteria.setProjection(null);
				paging.setItemsCount(totalCount);
				paging.setItems(criteria.setFirstResult(paging.getStartIndex()).setMaxResults(paging.getPageSize())
						.list());
				return paging;
			}
		});
	}

	public int excuteUpdate(final String hql, final Object[] values) {
		Object o = getHibernateTemplate().execute(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Transaction tx = session.beginTransaction();
				Query query = session.createQuery(hql);
				if (values != null && values.length > 0) {
					for (int i = 0; i < values.length; i++) {
						query.setParameter(i, values[i]);
					}
				}
				int i = 0;
				try {
					i = query.executeUpdate();
					tx.commit();
				} catch (Exception e) {
					tx.rollback();
				}
				return i;
			}
		});
		return (Integer) o;
	}

}
